package com.binfenhulian.chinaenergy.ces.crawler.pipeline.impl;

import com.binfenhulian.chinaenergy.ces.core.exception.BaseException;
import com.binfenhulian.chinaenergy.ces.crawler.constants.Constants;
import com.binfenhulian.chinaenergy.ces.crawler.core.db.dao.def.ContentRecordDefDAO;
import com.binfenhulian.chinaenergy.ces.crawler.core.db.enums.ContentRecordTypeEnum;
import com.binfenhulian.chinaenergy.ces.crawler.core.db.po.auto.ContentRecordPO;
import com.binfenhulian.chinaenergy.ces.crawler.pipeline.PersistentService;
import com.binfenhulian.chinaenergy.ces.utils.collections.ListUtils;
import com.binfenhulian.chinaenergy.ces.utils.date.UnixTimestampUtils;
import com.binfenhulian.chinaenergy.ces.utils.uuid.UuidUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import us.codecraft.webmagic.ResultItems;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * 数据库持久化
 * Created by wanghjbuf on 2018/3/10.
 */
@Slf4j
@Component("com.binfenhulian.chinaenergy.ces.crawler.pipeline.impl.DbServiceImpl")
public class DbServiceImpl implements PersistentService {

    @Autowired
    ContentRecordDefDAO contentRecordDefDAO;
    @Autowired
    Constants constants;
    @Resource(name = "defRedisTemplate")
    RedisTemplate<String, Object> redisTemplate;

    /**
     * 执行存储
     * @param resultItems
     */
    @Override
    public void doStore(ResultItems resultItems) {
        String crawler_no = resultItems.get("crawler_no");
        //TODO 存在队列不等长问题
        List<String> urls = resultItems.get("list_url");
        List<String> contents = resultItems.get("list_content");

        List<ContentRecordPO> insertContentRecordPOList = new ArrayList<>();
        List<String> updateContentRecordPOList = new ArrayList<>();
        for (int i=0; i<urls.size(); i++) {
            String url = urls.get(i);
            String content = contents.get(i);
            StringBuffer redisUrlKey = new StringBuffer(constants.CRAWLER_REDIS_SEED_URL_KEY_PREFIX).append(url);

            if (redisTemplate.hasKey(redisUrlKey.toString())) {
                updateContentRecordPOList.add(url);
            } else {
                redisTemplate.opsForValue().set(redisUrlKey.toString(), "true");

                int currentTimes = UnixTimestampUtils.currentTimes();
                ContentRecordPO contentRecordPO = new ContentRecordPO();
                contentRecordPO.setNo(UuidUtils.getUUID());
                contentRecordPO.setFirstDiscovery(currentTimes);
                contentRecordPO.setRecentlyDiscovery(currentTimes);
                contentRecordPO.setTitle(content);
                contentRecordPO.setUrl(url);
                contentRecordPO.setType(ContentRecordTypeEnum.AUTO.name());
                contentRecordPO.setUseCount(0);
                contentRecordPO.setCreateTime(currentTimes);
                contentRecordPO.setUpdateTime(currentTimes);
                contentRecordPO.setCrawlerNo(crawler_no);
                insertContentRecordPOList.add(contentRecordPO);
            }
        }

        try{
            insertPOList(insertContentRecordPOList);
        }catch (BaseException e){
            insertContentRecordPOList.forEach(item ->{
                StringBuffer redisUrlKey = new StringBuffer(constants.CRAWLER_REDIS_SEED_URL_KEY_PREFIX).append(item.getUrl());
                redisTemplate.delete(redisUrlKey.toString());
            });
            throw  e;
        }

        updatePOList(updateContentRecordPOList);
    }

    /**
     * 插入
     * @param insertContentRecordPOList
     */
    @Transactional
    public void insertPOList(List<ContentRecordPO> insertContentRecordPOList) throws BaseException{
        try{
            if (insertContentRecordPOList.size() > 0) {
                ListUtils.splitList(insertContentRecordPOList, 100).forEach(itemList ->{
                    log.info("insert-count:{};", contentRecordDefDAO.insertBatch((List<ContentRecordPO>) itemList));
                });
            }
        } catch (Exception e){
            throw new BaseException("DB-插入操作发生错误,操作失败!", e);
        }
    }

    /**
     * 更新
     * @param updateContentRecordPOList
     */
    @Transactional
    public  void  updatePOList(List<String> updateContentRecordPOList) throws BaseException{
        try{
            if (updateContentRecordPOList.size() > 0) {
                ListUtils.splitList(updateContentRecordPOList, 100).forEach(itemList ->{
                    log.info("update-count:{};", contentRecordDefDAO.updateBatchByUrlForDiscoveryTime((List<String>) itemList));
                });
            }
        }catch (Exception e){
            throw  new BaseException("DB-更新操作发生错误,操作失败!", e);
        }
    }
}

